home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume23 / newsxd / part02 < prev    next >
Encoding:
Internet Message Format  |  1990-10-09  |  52.5 KB

  1. Subject:  v23i012:  Netnews transmission daemon, Part02/03
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: b4e97780 d0334675 2eef814a 67669e60
  5.  
  6. Submitted-by: Chris Myers <chris@wugate.wustl.edu>
  7. Posting-number: Volume 23, Issue 12
  8. Archive-name: newsxd/part02
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  defs.h patchlevel.h process.c simple.conf util.c version.c
  17. # Wrapped by rsalz@litchi.bbn.com on Fri Jul 13 15:03:57 1990
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive 2 (of 3)."'
  21. if test -f 'defs.h' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'defs.h'\"
  23. else
  24.   echo shar: Extracting \"'defs.h'\" \(6742 characters\)
  25.   sed "s/^X//" >'defs.h' <<'END_OF_FILE'
  26. X/* Define everything that all of the various pieces of code will be using */
  27. X
  28. X#include <stdio.h>
  29. X#include <signal.h>
  30. X#include <strings.h>
  31. X#include <syslog.h>
  32. X#include <nlist.h>
  33. X#include <errno.h>
  34. X#include <ctype.h>
  35. X#include <sys/param.h>
  36. X#include <sys/errno.h>
  37. X#include <sys/file.h>
  38. X#include <sys/ioctl.h>
  39. X#include <sys/wait.h>
  40. X#include <sys/types.h>
  41. X#include <sys/stat.h>
  42. X#include <varargs.h>
  43. X
  44. X#include "newsxd.h"
  45. X#include "patchlevel.h"
  46. X
  47. X/* If it's good enough for news 2.11, it's good enough for me ... */
  48. X
  49. X#ifdef BSD4_2
  50. X#include <sys/time.h>
  51. X#else
  52. X#include <time.h>
  53. X#endif
  54. X
  55. X#include <sys/resource.h>
  56. X
  57. X#if defined(mips) & defined(ultrix)
  58. X#include <sys/../h/fixpoint.h>
  59. X#endif
  60. X
  61. Xchar    *calloc();
  62. X
  63. X#define foreach(ctl, list) for (ctl = list; ctl != NULL; ctl = ctl->next)
  64. X
  65. X#ifdef    CNEWSLOCKING
  66. Xextern char    *progname;
  67. X#endif
  68. X
  69. Xint     debug,                  /* is debugging enabled                       */
  70. X        DEBUG,                  /* painfully verbose debugging is enabled     */
  71. X        newsxdebug,             /* run xmitter synchronously with debugging?  */
  72. X        tallying,               /* is use of a tally file enabled?            */
  73. X        locking,                /* is use of a locking file enabled?          */
  74. X        CONFIGCHANGED,          /* a new configuration was read in            */
  75. X#ifdef FAKESYSLOG
  76. X        CONFIGCHANGEDFILE,      /* a new configuration was read in            */
  77. X#endif
  78. X        queueinterval,          /* number of seconds between xmit checks      */
  79. X    daemon_idle,        /* prevent newsxd from running queue if set   */
  80. X        pidlist[MAXXMITTERS];   /* map pid --> xmitter quicker                */
  81. X
  82. Xstruct    host    *pidmap[MAXXMITTERS];
  83. X
  84. Xchar    batchfile[MAXPATHLEN],  /* file inews places article IDs/paths in     */
  85. X        workfile[MAXPATHLEN],   /* file to use for transmitter work file      */
  86. X        xmitlogs[MAXPATHLEN],   /* where to log the output of transmitters    */
  87. X        tallyfile[MAXPATHLEN],  /* where the tally file can be found          */
  88. X        statusfile[MAXPATHLEN], /* where newsxd's status should be written    */
  89. X        pidfile[MAXPATHLEN],    /* where newsxd's pid should be written       */
  90. X#ifdef FAKESYSLOG
  91. X        fakelogfile[MAXPATHLEN],/* where is the newsxd log file?              */
  92. X#endif
  93. X        configfile[MAXPATHLEN]; /* where is the newsxd configuration file?    */
  94. X
  95. X/* STRUCT OPTIONS
  96. X * Used to define the options controlling the starting of transmitters for
  97. X * classes and hosts.
  98. X *
  99. X * interval   : minimum start-to-start interval for each host's transmitter
  100. X * startint   : minimum interval between starting transmitters in this class
  101. X * ttl        : maximum time-to-live (secs) for a transmitter in this class
  102. X * ttlpenalty : penalty time (secs) for a transmitter exceeding the ttl
  103. X * deltanice  : amount to change nice before execing the transmitter
  104. X * maxload    : maximum load where new xmitters can be started for this class
  105. X *
  106. X */
  107. X
  108. Xtypedef struct options {
  109. X
  110. X    int    deltanice;
  111. X    int    interval;
  112. X    int    startint;
  113. X    int    ttl;
  114. X    int    ttlpenalty;
  115. X    int    maxload;
  116. X    
  117. X};
  118. X
  119. X/*
  120. X * STRUCT CLASS
  121. X * Contains the current state and description of each class of transmitters
  122. X * that newsxd handles.
  123. X *
  124. X * classname  : textual name of this transmission class
  125. X * maxxmits   : maximum number of simultaneous transmitters for this class
  126. X * curxmits   : current number of active transmitters for this class
  127. X * laststart  : last time a transmitter was started for this class
  128. X * xmitsernum : transmission serial number used for fair news transmission
  129. X * options    : defines default transmitter startup parameters for this class
  130. X * members    : number of hosts that are a member of this class
  131. X * flags      : special option flags for this class
  132. X *                0 : don't rename <batchfile> to <workfile>
  133. X *                1 : don't look for <batchfile> or <workfile>
  134. X * xpath      : file path for an alternate transmission program
  135. X * xargv      : arguments to be passed to the alternate transmitter
  136. X * xargc      : number of arguments to be passed to the alternate xmitter
  137. X * valid      : used to detect which classes are valid after a config update
  138. X * next       : pointer to the next class descriptor in the list
  139. X *
  140. X */
  141. X
  142. Xstruct  class {
  143. X
  144. X        char    classname[MAXCLASSNAMELEN];
  145. X        int     maxxmits;
  146. X        int     curxmits;
  147. X        int     laststart;
  148. X        int     xmitsernum;
  149. X        int     members;
  150. X    struct    options    options;
  151. X    char    slots[MAXCLASSXMITTERS];
  152. X        int     flags[MAXCLASSFLAGS];
  153. X    char    batchfile[MAXPATHLEN];
  154. X    char    workfile[MAXPATHLEN];
  155. X        char    xpath[MAXPATHLEN];
  156. X        char    *xargv[MAXEXECARGS];
  157. X        int     xargc;
  158. X        char    *debugargv[MAXEXECARGS];
  159. X        int     debugargc;
  160. X        int     valid;
  161. X        struct  class   *next;
  162. X
  163. X};
  164. X
  165. X/*
  166. X * STRUCT HOST
  167. X * Contains the current state and description of each host that newsxd
  168. X * will be communicating with.
  169. X *
  170. X * hostname    : name of the host to pass to the transmitter
  171. X * class       : name of the transmission class this host is in
  172. X * times       : list of valid times to transmit in UUCP L.sys format
  173. X * pid         : pid of forked transmitter
  174. X * lasttime    : last time transmitter was forked off
  175. X * xmitsernum  : transmission serial number used for fair news transmission
  176. X * penaltytime : host xmitted to past ttl; secs before penalty is over
  177. X * whynot      : why is there no transmitter running for this host NOW?
  178. X * valid       : used to detect which hosts are valid after a config update
  179. X * options     : defines default transmitter startup parameters for this host
  180. X * next        : pointer to next host in the list of all hosts
  181. X * xargv       : arguments to be passed to the transmitter
  182. X * xargc       : number of arguments to be passed to the transmitter
  183. X *
  184. X */
  185. X
  186. Xstruct  host {
  187. X
  188. X        char    hostname[MAXHOSTNAMELEN];
  189. X        char    class[MAXCLASSNAMELEN];
  190. X        char    times[MAXTIMENAMELEN];
  191. X        int     pid;
  192. X        int     lasttime;
  193. X        int     penaltytime;
  194. X        int     xmitsernum;
  195. X        int     whynot;
  196. X        int     valid;
  197. X    int    classslot;
  198. X    struct    options    options;
  199. X        char    *xargv[MAXEXECARGS];
  200. X        int     xargc;
  201. X        struct  host    *next;
  202. X
  203. X};
  204. X
  205. Xstruct  class   *classlist;
  206. Xstruct  host    *hostlist;
  207. X
  208. X/* Predefine the return types of all of the functions */
  209. X
  210. Xvoid    addclass();
  211. Xvoid    addhost();
  212. Xvoid    clear_invalid();
  213. Xvoid    daemon_start();
  214. Xvoid    debug_off();
  215. Xvoid    debug_on();
  216. Xvoid    dprintf();
  217. Xvoid    Dprintf();
  218. Xvoid    dump_config();
  219. Xvoid    dump_info();
  220. Xvoid    idle();
  221. Xvoid    reset();
  222. Xstruct    class    *getclass();
  223. Xvoid    freeclassslot();
  224. Xint    getclassslot();
  225. Xint    getla();
  226. Xvoid    kill_children();
  227. Xvoid    log();
  228. Xvoid    logerr();
  229. Xvoid    make_invalid();
  230. Xint    parsetime();
  231. Xvoid    processarg();
  232. Xvoid    read_config();
  233. Xvoid    run_queue();
  234. Xint    validtime();
  235. Xvoid    xmit_done();
  236. END_OF_FILE
  237.   if test 6742 -ne `wc -c <'defs.h'`; then
  238.     echo shar: \"'defs.h'\" unpacked with wrong size!
  239.   fi
  240.   # end of 'defs.h'
  241. fi
  242. if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  243.   echo shar: Will not clobber existing file \"'patchlevel.h'\"
  244. else
  245.   echo shar: Extracting \"'patchlevel.h'\" \(41 characters\)
  246.   sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
  247. X#define VERSION 2.5
  248. X#define PATCHLEVEL 1
  249. END_OF_FILE
  250.   if test 41 -ne `wc -c <'patchlevel.h'`; then
  251.     echo shar: \"'patchlevel.h'\" unpacked with wrong size!
  252.   fi
  253.   # end of 'patchlevel.h'
  254. fi
  255. if test -f 'process.c' -a "${1}" != "-c" ; then 
  256.   echo shar: Will not clobber existing file \"'process.c'\"
  257. else
  258.   echo shar: Extracting \"'process.c'\" \(20001 characters\)
  259.   sed "s/^X//" >'process.c' <<'END_OF_FILE'
  260. X/*
  261. X * #include <legal/bs.h>
  262. X >
  263. X > Copyright (c) 1989 Washington University in Saint Louis, Missouri and
  264. X > Chris Myers. All rights reserved.
  265. X >
  266. X > Permission is hereby granted to copy, reproduce, redistribute or
  267. X > otherwise use this software as long as: (1) there is no monetary
  268. X > profit gained specifically from the use or reproduction of this
  269. X > software, (2) it is not sold, rented, traded, or otherwise marketed,
  270. X > (3) the above copyright notice and this paragraph is included
  271. X > prominently in any copy made, and (4) that the name of the University
  272. X > is not used to endorse or promote products derived from this software
  273. X > without the specific prior written permission of the University.
  274. X > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  275. X > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  276. X > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  277. X >
  278. X */
  279. X
  280. X#include "defs.h"
  281. Xextern int errno;
  282. X
  283. X/*************************************************************************/
  284. X/* FUNCTION  : kill_children                                             */
  285. X/* PURPOSE   : Kills all outstanding transmitters.  Kill_children will   */
  286. X/*             wait thirty seconds to allow all of the transmitters to   */
  287. X/*             exit gracefully.  If invoked by a signal (SIGTERM?), exit */
  288. X/*             else return to caller.                                    */
  289. X/* ARGUMENTS : Signal number or 0 if to return to caller                 */
  290. X/*************************************************************************/
  291. X
  292. Xvoid
  293. Xkill_children(sig)
  294. X   int  sig;            /* sig will be nonzero if called by SIGTERM */
  295. X
  296. X{
  297. Xstruct  host    *hostptr;
  298. X
  299. X   if ((hostlist == NULL) && (sig == 0)) return;
  300. X
  301. X   log(LOG_INFO, "newsxd: shutting down all transmitters\n");
  302. X
  303. X   foreach (hostptr, hostlist) {
  304. X      if (hostptr->pid != 0) {
  305. X         dprintf("newsxd: killing transmitter for %s\n", hostptr->hostname);
  306. X         (void) kill (hostptr->pid, SIGTERM);
  307. X      }
  308. X   }
  309. X
  310. X   if (sig == 0) return;
  311. X
  312. X   dprintf("(kill_children): sleeping 30 seconds\n");
  313. X
  314. X   (void) sleep(30);            /* allow transmitters to quit gracefully */
  315. X
  316. X   log(LOG_INFO, "shut down by signal %d\n", sig);
  317. X
  318. X   if (debug == 0 && DEBUG == 0) {
  319. X      (void) unlink(pidfile);
  320. X      (void) unlink(statusfile);
  321. X   }
  322. X
  323. X   (void) exit(0);              /* invoked by SIGTERM, time to quit */
  324. X
  325. X}
  326. X
  327. X/*************************************************************************/
  328. X/* FUNCTION  : xmit_done                                                 */
  329. X/* PURPOSE   : Catch the SIGCHLD from completed transmitters and do the  */
  330. X/*             necessary cleanup.  Also wait synchronously for a xmitter */
  331. X/*             to complete; also perform forced cleanup for an xmitter   */
  332. X/* ARGUMENTS : sig, > 0 if xmit_done is called by SIGCHLD                */
  333. X/*                 == 0 if called to check for a zombie w/NOHANG         */
  334. X/*                 ==-1 if called to sync wait for a transmitter         */
  335. X/*                 < -1 to perform a forced cleanup on a transmitter     */
  336. X/*************************************************************************/
  337. X
  338. Xvoid
  339. Xxmit_done(sig)
  340. X   int  sig;                 /* sig will be nonzero if called by SIGCHLD */
  341. X
  342. X{
  343. Xstruct  host    *hostptr;
  344. Xstruct  class   *classptr;
  345. Xunion   wait    status;
  346. Xstruct  rusage  usage;
  347. Xextern    char    *sys_errlist[];
  348. X
  349. Xint     options,
  350. X    loop,
  351. X        pid;
  352. X
  353. X   (void) sigsetmask(0);
  354. X
  355. X   /*
  356. X    * Try and catch any completed transmitters first and process them.
  357. X    * Then, if xmit_done() was called to synchronously wait on a transmitter
  358. X    * or to perform forced cleanup on a transmitter, do it.
  359. X    */
  360. X
  361. X   Dprintf("(xmit_done) sig %d\n", sig);
  362. X
  363. X   while (1) {
  364. X      if (sig != -1) options = WNOHANG;
  365. X
  366. X      pid = wait3(&status, options, &usage);
  367. X
  368. X      if (pid <= 0) 
  369. X         if (sig < -1) {
  370. X            pid = -sig;
  371. X            sig = 0;
  372. X         } else {
  373. X            Dprintf("(xmit_done) no process! pid=%d, errno=%s\n", pid,
  374. X               sys_errlist[errno]);
  375. X            return;
  376. X         }
  377. X   
  378. X      Dprintf("(xmit_done) pid %d\n", pid);
  379. X
  380. X      for (loop = 0; loop < MAXXMITTERS; loop++) {
  381. X         if (pidlist[loop] == pid) {
  382. X            hostptr = pidmap[loop];
  383. X            pidlist[loop] = 0;
  384. X            pidmap[loop] = (struct host *) NULL;
  385. X            hostptr->pid = 0;
  386. X            hostptr->whynot = WN_NOTMYTURN;
  387. X            foreach (classptr, classlist) {
  388. X               if (strcmp(hostptr->class, classptr->classname) == 0) {
  389. X                  classptr->curxmits--;
  390. X                  freeclassslot(classptr, hostptr->classslot);
  391. X                  dprintf("%s: transmission completed\n", hostptr->hostname);
  392. X                  return;
  393. X               }
  394. X            }
  395. X
  396. X            /*
  397. X             * The (sig < -1) check is here just in case a transmitter exitted
  398. X             * normally just as run_queue tries to force a cleanup on it. If
  399. X             * this isn't here, newsxd will abort with a corrupted data err.
  400. X             */
  401. X
  402. X            if (sig < -1) return;
  403. X
  404. X            /* Something is seriously wrong here -- quit somewhat gracefully */
  405. X
  406. X            logerr("CORRUPTED HOST/CLASS STRUCTURE!\n");
  407. X            kill_children(1);
  408. X         }
  409. X      }
  410. X   }
  411. X}
  412. X
  413. X/*************************************************************************/
  414. X/* FUNCTION  : run_queue                                                 */
  415. X/* PURPOSE   : Go through the list of hosts to transmit to and start any */
  416. X/*             transmitter that meets all of the necessary conditions    */
  417. X/* ARGUMENTS : none                                                      */
  418. X/*************************************************************************/
  419. X
  420. Xvoid
  421. Xrun_queue()
  422. X
  423. X{
  424. Xstruct  host    *hostptr;
  425. Xstruct  class   *classptr, *lastclass;
  426. Xstruct  stat    statbuf;
  427. Xstruct  tm      *curtime;
  428. X
  429. Xint     clock,
  430. X        pid,
  431. X        hadtheirchance,
  432. X    which,
  433. X    which2,
  434. X        loop,
  435. X        loop2,
  436. X    hostargc,
  437. X    classargc;
  438. X
  439. Xchar    fnbuf[MAXPATHLEN],
  440. X        fnbuf2[MAXPATHLEN],
  441. X    **hostargv,
  442. X    **classargv;
  443. X
  444. X   CONFIGCHANGED = 0;
  445. X   hadtheirchance = 0;
  446. X   lastclass = (struct class *) NULL;
  447. X
  448. X   foreach (hostptr, hostlist) {
  449. X
  450. X      /*
  451. X       * If the configuration has been changed (possibly via SIGHUP), we
  452. X       * need to assume that all of the current pointers and such are
  453. X       * invalid since the current host MAY have been deleted...
  454. X       *
  455. X       * There is still a race condition, but this check lessens the chance
  456. X       * of problems considerably.
  457. X       *
  458. X       */
  459. X
  460. X      if (CONFIGCHANGED) {
  461. X         dprintf("Reconfigured during queue run -- aborting queue run\n");
  462. X         CONFIGCHANGED = 0;
  463. X         return;
  464. X      }
  465. X
  466. X      (void) time(&clock);
  467. X      curtime = localtime(&clock);
  468. X
  469. X      classptr = getclass(hostptr->class);
  470. X
  471. X      if (classptr != lastclass) {
  472. X         if (lastclass) {
  473. X            dprintf("class %s: members %d, hadtheirchance %d\n",
  474. X               lastclass->classname, lastclass->members, hadtheirchance);
  475. X            if (lastclass->members == hadtheirchance) {
  476. X               lastclass->xmitsernum++;
  477. X               dprintf("class %s: add 1 to xmitsernum, now %d\n",
  478. X                  lastclass->classname, lastclass->xmitsernum);
  479. X            }
  480. X         }
  481. X         hadtheirchance = 0;
  482. X         lastclass = classptr;
  483. X      }
  484. X
  485. X      /*
  486. X       * Check and see if we somehow missed the SIGCHLD for a transmitter and
  487. X       * it's really gone and we don't know it.  If so, force a cleanup.
  488. X       */
  489. X
  490. X      if ((hostptr->pid) && (kill(hostptr->pid, 0) == -1) && (errno == ESRCH)) {
  491. X         xmit_done(-hostptr->pid);
  492. X         hostptr->pid = 0;          /* Just in case xmit_done() missed it! */
  493. X      }
  494. X
  495. X      /*
  496. X       * Check to see if the host has had a transmitter running for more
  497. X       * than the ttl of its transmission class.  If so, kill it.
  498. X       */
  499. X
  500. X      which = (hostptr->options.ttl) ?
  501. X         hostptr->options.ttl : classptr->options.ttl;
  502. X      which2 = (hostptr->options.ttlpenalty) ?
  503. X         hostptr->options.ttlpenalty : classptr->options.ttlpenalty;
  504. X
  505. X      dprintf("%s: checking ttl (%d/%d)\n", hostptr->hostname, which, which2);
  506. X
  507. X      if ((hostptr->pid > 0) && (clock > (hostptr->lasttime + which))) {
  508. X         dprintf("%s: exceeded ttl, killing\n");
  509. X         hostptr->penaltytime = clock + which2;
  510. X         if (kill(hostptr->pid, SIGTERM) != 0) xmit_done(-hostptr->pid);
  511. X         hostptr->whynot = WN_TTL;
  512. X         continue;  /* skip this host to give others a chance */
  513. X      }
  514. X
  515. X      /*
  516. X       * If there is already a running transmitter for this host, skip it. We
  517. X       * don't want more than one!
  518. X       */
  519. X
  520. X      dprintf("%s: checking for active daemon (%d)\n", hostptr->hostname,
  521. X         hostptr->pid);
  522. X
  523. X      if (hostptr->pid > 0) {
  524. X         hostptr->whynot = WN_RUNNING;
  525. X         hadtheirchance++;
  526. X         continue;
  527. X      }
  528. X
  529. X      /*
  530. X       * Check to see if this host has already had a chance to start
  531. X       * a transmitter.  If so, let someone else have a chance.
  532. X       */
  533. X
  534. X      dprintf("%s: xmitsernum is %d, class xmitsernum is %d\n",
  535. X         hostptr->hostname, hostptr->xmitsernum, classptr->xmitsernum);
  536. X
  537. X/*
  538. X      if ((hostptr->xmitsernum == classptr->xmitsernum) &&
  539. X          (classptr->maxxmits < classptr->members)) {
  540. X */
  541. X
  542. X      if (hostptr->xmitsernum == classptr->xmitsernum) {
  543. X         hadtheirchance++;
  544. X/*       hostptr->whynot = WN_NOTMYTURN; */
  545. X         continue;
  546. X      }
  547. X
  548. X      /*
  549. X       * Check the current time against the last time an xmit was started
  550. X       * for this class to make sure we don't start too many daemons at
  551. X       * one time.
  552. X       */
  553. X
  554. X      which = (hostptr->options.startint) ?
  555. X         hostptr->options.startint : classptr->options.startint;
  556. X
  557. X      dprintf("%s: checking class startup interval (clock is %d, start %d)\n",
  558. X         hostptr->hostname, clock, (classptr->laststart + which));
  559. X
  560. X      if (clock < (classptr->laststart + which)) {
  561. X         hostptr->whynot = WN_CLASSSTARTINT;
  562. X         continue;
  563. X      }
  564. X
  565. X      /*
  566. X       * Check the current load and compare against the maximum allowed
  567. X       * load for starting new transmitters for this hosts's class.
  568. X       */
  569. X
  570. X      which = (hostptr->options.maxload) ?
  571. X         hostptr->options.maxload : classptr->options.maxload;
  572. X
  573. X      dprintf("%s: checking maximum load (cur %d, max %d)\n",
  574. X         hostptr->hostname, getla(), which);
  575. X
  576. X      if (getla() > which) {
  577. X         hostptr->whynot = WN_LOAD;
  578. X         continue;
  579. X      }
  580. X
  581. X      /*
  582. X       * Check the number of currently running transmitters for this host's
  583. X       * transmission class.  If we're already running at the limit, skip
  584. X       * this host.
  585. X       */
  586. X
  587. X      dprintf("%s (%s): checking running xmit count (%d of %d)\n",
  588. X         hostptr->hostname, classptr->classname, classptr->curxmits,
  589. X         classptr->maxxmits);
  590. X
  591. X      if (classptr->curxmits >= classptr->maxxmits) {
  592. X         hostptr->whynot = WN_MAXXMITS;
  593. X         continue;
  594. X      }
  595. X
  596. X      /*
  597. X       * All tests after this point should be tests for some characteristic
  598. X       * of the host that would cause it to avoid its turn to start its
  599. X       * transmitter.  Things like: the host startup interval hasn't passed
  600. X       * yet, or it's a bad time to send to that host, or there's no work
  601. X       * to send to that host.
  602. X       *
  603. X       * Tests before this point should be tests for some characteristic not
  604. X       * related to the particular host that prevents it from being able to
  605. X       * start its transmitter.  Things like: load too high, too many xmits
  606. X       * already running...
  607. X       */
  608. X
  609. X      /*
  610. X       * This host had a chance to send news (and can possibly skip it).
  611. X       */
  612. X
  613. X      hostptr->xmitsernum = classptr->xmitsernum;
  614. X      hadtheirchance++;
  615. X
  616. X      /*
  617. X       * Check to see if the host had a transmitter killed because it ran
  618. X       * longer than its class' ttl.  If so, see if its penalty time is
  619. X       * still unexpired.
  620. X       */
  621. X
  622. X      dprintf("%s: checking ttl penalty\n", hostptr->hostname);
  623. X
  624. X      if (hostptr->penaltytime > clock) {
  625. X         hostptr->whynot = WN_PENALTYTIME;
  626. X         continue;
  627. X      }
  628. X
  629. X      /*
  630. X       * Check the current time against the last time an xmit was started
  631. X       * for this class to make sure we don't start a transmitter for this
  632. X       * host too often...
  633. X       */
  634. X
  635. X      which = (hostptr->options.interval) ?
  636. X         hostptr->options.interval : classptr->options.interval;
  637. X
  638. X      dprintf("%s: checking host startup interval (%d)\n", hostptr->hostname,
  639. X         which);
  640. X
  641. X      if (clock < (hostptr->lasttime + which)) {
  642. X         hostptr->whynot = WN_HOSTSTARTINT;
  643. X         continue;
  644. X      }
  645. X
  646. X      /*
  647. X       * Check to see that the current time is within the permitted range
  648. X       * of transmission times.  If not, skip this host.
  649. X       */
  650. X
  651. X      dprintf("%s: checking valid transmission times (%s)\n",
  652. X         hostptr->hostname, hostptr->times);
  653. X
  654. X      if (!validtime(hostptr->times)) {
  655. X         hostptr->whynot = WN_BADTIME;
  656. X         continue;
  657. X      }
  658. X
  659. X      /*
  660. X       * See if there is an outstanding work file for this host, if so we
  661. X       * just need to run a transmitter, otherwise rename the batch file
  662. X       * to the work file and run the transmitter.
  663. X       */
  664. X
  665. X      (void) sprintf(fnbuf, workfile, hostptr->hostname);
  666. X
  667. X      dprintf("%s: checking for workfile (%s)\n",
  668. X            hostptr->hostname, fnbuf);
  669. X
  670. X      if ((loop = stat(fnbuf, &statbuf)) != 0) {
  671. X         Dprintf("%s: stat(%s) returned %d (errno is %d)\n", hostptr->hostname,
  672. X            fnbuf, loop, errno);
  673. X
  674. X         (void) sprintf(fnbuf2, batchfile, hostptr->hostname);
  675. X
  676. X         dprintf("%s: checking for batchfile (%s)\n",
  677. X               hostptr->hostname, fnbuf2);
  678. X
  679. X         if (!classptr->flags[C_NOBATCH]) {
  680. X            if ((loop = stat(fnbuf2, &statbuf)) != 0) {
  681. X               Dprintf("%s: stat(%s) returned %d (errno is %d)\n",
  682. X                  hostptr->hostname, fnbuf, loop, errno);
  683. X
  684. X               hostptr->whynot = WN_NOWORK;
  685. X               continue;
  686. X            } else {
  687. X               hostptr->whynot = WN_RENAMEFAILED;
  688. X               if (!classptr->flags[C_NOWORK] && rename(fnbuf2, fnbuf) != 0) {
  689. X                  dprintf("%s: rename failed (%s to %s)\n",
  690. X                        hostptr->hostname, fnbuf2, fnbuf);
  691. X                  continue;
  692. X               }
  693. X            }
  694. X         }
  695. X      }
  696. X      
  697. X      /*
  698. X       * Fork off a transmitter for this host
  699. X       */
  700. X
  701. X      hostptr->whynot = WN_RUNNING;
  702. X
  703. X      if ((hostptr->classslot = getclassslot(classptr)) == -1) {
  704. X         hostptr->whynot = WN_NOSLOT;
  705. X         exit(1);
  706. X      }
  707. X
  708. X      if ((pid = fork()) == 0) {
  709. X     /* Child. */
  710. X         int fd;
  711. X
  712. X         /* Untrap all of the signals for newsxd; this is now a transmitter */
  713. X
  714. X         (void) signal(SIGCHLD, SIG_DFL);
  715. X         (void) signal(SIGHUP, SIG_DFL);
  716. X         (void) signal(SIGQUIT, SIG_DFL);
  717. X         (void) signal(SIGTERM, SIG_DFL);
  718. X         (void) signal(SIGUSR1, SIG_DFL);
  719. X         (void) signal(SIGUSR2, SIG_DFL);
  720. X         (void) signal(SIGIO, SIG_DFL);
  721. X         (void) signal(SIGIOT, SIG_DFL);
  722. X         (void) signal(SIGTRAP, SIG_DFL);
  723. X
  724. X         fd = open(classptr->flags[C_NOWORK] ? fnbuf2 : fnbuf, O_RDONLY);
  725. X         if (fd > 0) (void) flock(fd, LOCK_EX);
  726. X
  727. X#ifdef    CNEWSLOCKING
  728. X         if (!classptr->flags[C_NOWORK]) {
  729. X
  730. X            /* If we can get a valid lock then we know that since the batch
  731. X             * file has been renamed to WORKFILE, cnews will now be writing
  732. X             * to a different file (BATCHFILE).
  733. X             */
  734. X            (void) newslock();
  735. X            (void) newsunlock();
  736. X         }
  737. X#endif    CNEWSLOCKING
  738. X
  739. X         Dprintf("(%s): classslot is %d\n", hostptr->hostname,
  740. X            hostptr->classslot);
  741. X
  742. X         dprintf("%s: spawning transmitter\n", hostptr->hostname);
  743. X
  744. X         if (!newsxdebug) {
  745. X            (void) sprintf(fnbuf2, xmitlogs, hostptr->hostname);
  746. X            (void) freopen(fnbuf2, "a", stdout);
  747. X            (void) freopen(fnbuf2, "a", stderr);
  748. X         }
  749. X
  750. X         (void) fprintf(stderr, "%s: begin at %02d:%02d:%02d\n",
  751. X            hostptr->hostname, curtime->tm_hour, curtime->tm_min,
  752. X            curtime->tm_sec);
  753. X         (void) fflush(stderr);
  754. X
  755. X         which = (hostptr->options.deltanice) ?
  756. X            hostptr->options.deltanice : classptr->options.deltanice;
  757. X
  758. X         if (which != 0) {
  759. X            Dprintf("Changing transmitter nice by %d for %s\n",
  760. X               which, hostptr->hostname);
  761. X
  762. X            (void) nice(which);
  763. X         }
  764. X
  765. X         if (classptr->xargc == 0) {
  766. X            classptr = getclass("DEFAULT");
  767. X            if (classptr->xargc == 0) {
  768. X               logerr("host %s: No DEFAULT xmitter defined -- aborting\n",
  769. X                  hostptr->hostname);
  770. X               (void) _exit(1);
  771. X            }
  772. X         }
  773. X
  774. X         Dprintf("classptr->xargc = %d\n", classptr->xargc);
  775. X
  776. X         Dprintf("%s: EXECing %s with parameters:\n",
  777. X            hostptr->hostname, classptr->xpath);
  778. X
  779. X         for (loop = 0; loop <= classptr->xargc; loop++) {
  780. X            if (classptr->xargv[loop] == NULL) {
  781. X               Dprintf("arg[%d] = NULL\n", loop);
  782. X            } else {
  783. X               Dprintf("arg[%d] = %s\n", loop, classptr->xargv[loop]);
  784. X            }
  785. X         }
  786. X
  787. X         classargc = classptr->xargc;
  788. X         classargv = classptr->xargv;
  789. X
  790. X         classargv[classargc] = NULL;
  791. X
  792. X         for (loop = 0; loop < classargc; loop++) {
  793. X            hostargv = NULL;
  794. X            if (strcmp(classargv[loop], "%f") == NULL) {
  795. X               hostargc = hostptr->xargc;
  796. X               hostargv = hostptr->xargv;
  797. X            }
  798. X
  799. X            if (strcmp(classargv[loop], "%d") == NULL) {
  800. X               struct class *myclassptr = getclass(hostptr->class);
  801. X               hostargc = myclassptr->debugargc;
  802. X               hostargv = myclassptr->debugargv;
  803. X               Dprintf("debug argc = %d\n", hostargc);
  804. X            }
  805. X
  806. X            if (hostargv != NULL) {
  807. X               if (hostargc == 0) {
  808. X                  classargc--;
  809. X                  for (loop2 = loop; loop2 < MAXEXECARGS-1; loop2++)
  810. X                     classargv[loop2] = classargv[loop2 + 1];
  811. X               } else {
  812. X                  classargc += hostargc - 1;
  813. X                  for (loop2 = MAXEXECARGS - hostargc; loop2 > loop; loop2--)
  814. X                     classargv[loop2 + hostargc - 1] = classargv[loop2];
  815. X                  for (loop2 = loop; loop2 < loop + hostargc; loop2++)
  816. X                     classargv[loop2] = hostargv[loop2 - loop];
  817. X                  loop += hostargc - 1;
  818. X               }
  819. X            }
  820. X         }
  821. X
  822. X         Dprintf("(after host flag insertion) classargc = %d\n",
  823. X            classargc);
  824. X
  825. X         for (loop = 0; loop <= classargc; loop++) {
  826. X            /* WARNING: we are mangling the xargv array here! */
  827. X            processarg(loop, hostptr, classptr);
  828. X
  829. X            if (classargv[loop] == NULL) {
  830. X               Dprintf("arg[%d] = NULL\n", loop);
  831. X            } else {
  832. X               Dprintf("arg[%d] = %s\n", loop, classargv[loop]);
  833. X            }
  834. X         }
  835. X
  836. X         (void) execvp(classptr->xpath, classargv);
  837. X
  838. X         logerr("%s: can't exec %s\n", hostptr->hostname, classptr->xpath);
  839. X
  840. X         (void) _exit(1); /* could not exec the news transmitter! */
  841. X      } else {
  842. X     /* Parent. */
  843. X     if (pid == -1) {
  844. X        logerr("host %s: Can't fork child.\n", hostptr->hostname);
  845. X        continue;
  846. X     }
  847. X         for (loop = 0; loop < MAXXMITTERS; loop++) {
  848. X            if (pidlist[loop] == 0) {
  849. X               pidlist[loop] = pid;
  850. X               pidmap[loop] = hostptr;
  851. X               Dprintf("%s: entered into pidmap/list at %d\n",
  852. X                  hostptr->hostname, loop);
  853. X               break;
  854. X            }
  855. X         }
  856. X         hostptr->pid = pid;
  857. X         hostptr->lasttime = clock;
  858. X         classptr->laststart = clock;
  859. X         classptr->curxmits++;
  860. X         if (newsxdebug) xmit_done(-1); /* wait for xmitter to complete */
  861. X      }
  862. X   }
  863. X
  864. X   if (classptr->members == hadtheirchance) {
  865. X      dprintf("class %s: add 1 to sernum (members %d, hadchance %d)\n",
  866. X         classptr->classname, classptr->members, hadtheirchance);
  867. X      classptr->xmitsernum++;
  868. X   }
  869. X}
  870. END_OF_FILE
  871.   if test 20001 -ne `wc -c <'process.c'`; then
  872.     echo shar: \"'process.c'\" unpacked with wrong size!
  873.   fi
  874.   # end of 'process.c'
  875. fi
  876. if test -f 'simple.conf' -a "${1}" != "-c" ; then 
  877.   echo shar: Will not clobber existing file \"'simple.conf'\"
  878. else
  879.   echo shar: Extracting \"'simple.conf'\" \(1073 characters\)
  880.   sed "s/^X//" >'simple.conf' <<'END_OF_FILE'
  881. X# Define a service class that just runs an nntpxmit to each host
  882. X# every hour.  Don't run nntpxmit if the load goes over 8.
  883. X
  884. Xclass   normal  maxxmits=1  interval=3600  maxload=8
  885. X
  886. X# Define the default news transmitter
  887. Xxmit    DEFAULT /usr/local/lib/news/nntpxmit nntpxmit %h:%w
  888. X
  889. X# Check the list of hosts every 10 minutes to see if we can send news to
  890. X# someone yet.
  891. Xqueueinterval    600
  892. X
  893. X# In all of the following options, %s is replaced by the host name of the
  894. X# system being sent to.
  895. X
  896. X# File news places articles paths/ids in
  897. Xbatchfile   /usr/spool/batch/%s
  898. X
  899. X# File a news transmitter wants articles paths/ids in
  900. Xworkfile    /usr/spool/batch/%s.work
  901. X
  902. X# Hosts to send news to.  Each line is of the format:
  903. X#                            CLASS   VALID START
  904. X# host HOSTNAME              NAME       TIMES
  905. X
  906. Xhost dorothy                 normal      Any
  907. Xhost toto                    normal      Any
  908. Xhost wizard                  normal      Any
  909. Xhost witch                   normal      Any
  910. Xhost tinman                  normal      Any
  911. Xhost lion                    normal      Any
  912. END_OF_FILE
  913.   if test 1073 -ne `wc -c <'simple.conf'`; then
  914.     echo shar: \"'simple.conf'\" unpacked with wrong size!
  915.   fi
  916.   # end of 'simple.conf'
  917. fi
  918. if test -f 'util.c' -a "${1}" != "-c" ; then 
  919.   echo shar: Will not clobber existing file \"'util.c'\"
  920. else
  921.   echo shar: Extracting \"'util.c'\" \(10869 characters\)
  922.   sed "s/^X//" >'util.c' <<'END_OF_FILE'
  923. X/*
  924. X * #include <legal/bs.h>
  925. X >
  926. X > Copyright (c) 1989 Washington University in Saint Louis, Missouri and
  927. X > Chris Myers. All rights reserved.
  928. X >
  929. X > Permission is hereby granted to copy, reproduce, redistribute or
  930. X > otherwise use this software as long as: (1) there is no monetary
  931. X > profit gained specifically from the use or reproduction of this
  932. X > software, (2) it is not sold, rented, traded, or otherwise marketed,
  933. X > (3) the above copyright notice and this paragraph is included
  934. X > prominently in any copy made, and (4) that the name of the University
  935. X > is not used to endorse or promote products derived from this software
  936. X > without the specific prior written permission of the University.
  937. X > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  938. X > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  939. X > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  940. X >
  941. X */
  942. X
  943. X#include "defs.h"
  944. X
  945. X/*************************************************************************/
  946. X/* FUNCTION  : daemon_start                                              */
  947. X/* PURPOSE   : To disassociate newsxd from the calling process so it can */
  948. X/*             run as a daemon.                                          */
  949. X/* ARGUMENTS : none                                                      */
  950. X/*************************************************************************/
  951. X
  952. Xvoid
  953. Xdaemon_start()
  954. X
  955. X{
  956. Xregister int    childpid, fd;
  957. Xextern   int    errno;
  958. X
  959. X   /* Ignore the terminal stop signals */
  960. X   (void) signal(SIGTTOU, SIG_IGN);
  961. X   (void) signal(SIGTTIN, SIG_IGN);
  962. X   (void) signal(SIGTSTP, SIG_IGN);
  963. X
  964. X   /* Fork and let the parent process exit */
  965. X   if ((childpid = fork()) < 0) {
  966. X      logerr("newsxd: can't fork to enter daemon mode\n");
  967. X      (void) exit(1);
  968. X   } else if (childpid > 0) exit(0);
  969. X
  970. X   /* Lose the process group */
  971. X   if (setpgrp(0, getpid()) == -1) {
  972. X      logerr("newsxd: can't change pgrp to enter daemon mode\n");
  973. X      (void) exit(1);
  974. X   }
  975. X
  976. X   /* Lose the controlling terminal */
  977. X   if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
  978. X      (void) ioctl(fd, TIOCNOTTY, (char *) NULL);
  979. X      (void) close(fd);
  980. X   }
  981. X
  982. X   /* Close any open files */
  983. X   for (fd = 0; fd < NOFILE; fd++) (void) close(fd);
  984. X   errno = 0;
  985. X
  986. X   /* Set a proper default umask */
  987. X   (void) umask(022);
  988. X}
  989. X
  990. X/*************************************************************************/
  991. X/* FUNCTION  : getla                                                     */
  992. X/* PURPOSE   : Return the current system load                            */
  993. X/* ARGUMENTS : none                                                      */
  994. X/* NOTES     : this code stolen from sendmail 5.61 which stole it from   */
  995. X/*             from something else...                                    */
  996. X/*************************************************************************/
  997. X
  998. Xint
  999. Xgetla()
  1000. X
  1001. X{
  1002. X#if defined(sun) | defined(mips)
  1003. Xlong    avenrun[3];
  1004. X#else
  1005. Xdouble  avenrun[3];
  1006. X#endif
  1007. Xextern  off_t lseek();
  1008. Xstatic  int     kmem = -1;
  1009. X
  1010. Xstatic    struct  nlist Nl[] =
  1011. X{
  1012. X        { "_avenrun" },
  1013. X#define X_AVENRUN       0
  1014. X        { 0 },
  1015. X};
  1016. X
  1017. X
  1018. X   if (kmem < 0) {
  1019. X      kmem = open("/dev/kmem", 0, 0);
  1020. X      if (kmem < 0) return (-1);
  1021. X      (void) ioctl(kmem, (int) FIOCLEX, (char *) 0);
  1022. X      (void) nlist("/vmunix", Nl);
  1023. X      if (Nl[0].n_type == 0) return (-1);
  1024. X   }
  1025. X
  1026. X   if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
  1027. X       read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
  1028. X   {
  1029. X      /* thank you Ian */
  1030. X      return (-1);
  1031. X   }
  1032. X#ifdef sun
  1033. X   return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
  1034. X#else
  1035. X#ifdef mips
  1036. X   return (FIX_TO_INT(avenrun[0]));
  1037. X#else
  1038. X   return ((int) (avenrun[0] + 0.5));
  1039. X#endif
  1040. X#endif
  1041. X}
  1042. X
  1043. X/*************************************************************************/
  1044. X/* FUNCTION  : processarg                                                */
  1045. X/* PURPOSE   : Do %value substitutions in xargv                          */
  1046. X/* ARGUMENTS : which value of argv to modify, hostptr, classptr          */
  1047. X/*************************************************************************/
  1048. X
  1049. Xvoid
  1050. Xprocessarg(which, hostptr, classptr)
  1051. X   int  which;
  1052. X   struct host  *hostptr;
  1053. X   struct class *classptr;
  1054. X
  1055. X{
  1056. Xchar    buf1[MAXPATHLEN],
  1057. X        buf2[MAXPATHLEN],
  1058. X        charbuf[2],
  1059. X        *newxargv,
  1060. X        *strptr;
  1061. X
  1062. X   if (classptr->xargv[which] == NULL) return;
  1063. X
  1064. X   charbuf[1] = '\0';
  1065. X   *buf1 = '\0';
  1066. X
  1067. X   for (strptr = classptr->xargv[which]; *strptr != '\0'; strptr++) {
  1068. X      if (*strptr != '%') {
  1069. X         charbuf[0] = *strptr;
  1070. X         (void) strcat(buf1, charbuf);
  1071. X      } else {
  1072. X         strptr++;
  1073. X         switch (*strptr) {
  1074. X            case 'h': (void) strcat(buf1, hostptr->hostname);
  1075. X                      break;
  1076. X            case 'f': (void) strcat(buf1, "%f");
  1077. X                      /* We shouldn't have seen a %f at this point! */
  1078. X                      break;
  1079. X            case 'd': (void) strcat(buf1, "%d");
  1080. X                      /* We shouldn't have seen a %d at this point! */
  1081. X                      break;
  1082. X            case 'b': (void) sprintf(buf2, batchfile, hostptr->hostname);
  1083. X                      (void) strcat(buf1, buf2);
  1084. X                      break;
  1085. X            case 'w': if (classptr->flags[C_NOWORK])
  1086. X                         (void) sprintf(buf2, batchfile, hostptr->hostname);
  1087. X                      else
  1088. X                         (void) sprintf(buf2, workfile, hostptr->hostname);
  1089. X                      (void) strcat(buf1, buf2);
  1090. X                      break;
  1091. X            case 's': (void) sprintf(buf2, "%d", hostptr->classslot);
  1092. X                      (void) strcat(buf1, buf2);
  1093. X                      break;
  1094. X            case '%': (void) strcat(buf1, "%"); /* %% changes to % */
  1095. X                      break;
  1096. X            default : strptr--;
  1097. X         }
  1098. X      }
  1099. X   }
  1100. X
  1101. X   newxargv = (char *) malloc(strlen(buf1) + 1);
  1102. X   (void) strcpy(newxargv, buf1);
  1103. X   classptr->xargv[which] = newxargv;
  1104. X
  1105. X}
  1106. X
  1107. X/*************************************************************************/
  1108. X/* FUNCTION  : parse_time                                                */
  1109. X/* PURPOSE   : Check a single valid-time-string against the current time */
  1110. X/*             and return whether or not a match occurs.                 */
  1111. X/* ARGUMENTS : a pointer to the time-string                              */
  1112. X/*************************************************************************/
  1113. X
  1114. Xint
  1115. Xparsetime(whattime)
  1116. Xchar    *whattime;
  1117. X
  1118. X{
  1119. Xstatic char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Wk" };
  1120. Xlong    clock;
  1121. Xstruct  tm *curtime;
  1122. Xint     wday, start, stop, ltime, validday, loop, match;
  1123. X
  1124. X   (void) time(&clock);
  1125. X   curtime = localtime(&clock);
  1126. X   wday = curtime->tm_wday;
  1127. X   validday = 0;
  1128. X   match = 1;
  1129. X
  1130. X   while (match && isalpha(*whattime) && isupper(*whattime)) {
  1131. X      match = 0;
  1132. X      for (loop = 0; loop < 8; loop++) {
  1133. X         if (strncmp(days[loop], whattime, 2) == NULL) {
  1134. X            whattime += 2;
  1135. X            match = 1;
  1136. X            if ((wday == loop) | ((loop == 7) && wday && (wday < 6))) {
  1137. X               validday = 1;
  1138. X            }
  1139. X         }
  1140. X      }
  1141. X   }
  1142. X
  1143. X   if (strncmp(whattime, "Any", 3) == NULL) {
  1144. X      validday = 1;
  1145. X      whattime += 3;
  1146. X   }
  1147. X
  1148. X   if (!validday) return 0;
  1149. X
  1150. X   if (sscanf(whattime, "%d-%d", &start, &stop) == 2) {
  1151. X      ltime = curtime->tm_min + 100 * curtime->tm_hour;
  1152. X      if ((start < stop) && ((ltime > start) & ltime < stop)) return 1;
  1153. X      if ((start > stop) && ((ltime > start) | ltime < stop)) return 1;
  1154. X   } else return 1;
  1155. X
  1156. X   return 0;
  1157. X}
  1158. X
  1159. X/*************************************************************************/
  1160. X/* FUNCTION  : validtime                                                 */
  1161. X/* PURPOSE   : Break apart a set of valid time-strings and pass them to  */
  1162. X/*             parse_time, returning whether or not ANY matches occurred */
  1163. X/* ARGUMENTS : a pointer to the time-string                              */
  1164. X/*************************************************************************/
  1165. X
  1166. Xint
  1167. Xvalidtime(ptr)
  1168. Xchar    *ptr;
  1169. X
  1170. X{
  1171. Xchar    *nextptr;
  1172. Xint    good;
  1173. X
  1174. X   while (1) {
  1175. X      nextptr = STRCHR(ptr, '|');
  1176. X      if (STRCHR(ptr, '|') == NULL) return(parsetime(ptr));
  1177. X      *nextptr = '\0';
  1178. X      good = parsetime(ptr);
  1179. X      *nextptr++ = '|';  /* gotta restore the | or things get skipped! */
  1180. X      if (good) return(1);
  1181. X      ptr = nextptr;
  1182. X   }
  1183. X}
  1184. X
  1185. X/*************************************************************************/
  1186. X/* FUNCTION  : getclassslot                                              */
  1187. X/* PURPOSE   :                                                           */
  1188. X/* ARGUMENTS : a pointer to the class structure                          */
  1189. X/* RETURNS   : the slot number                                           */
  1190. X/*************************************************************************/
  1191. X
  1192. Xint    getclassslot(classptr)
  1193. Xstruct    class    *classptr;
  1194. X
  1195. X{
  1196. Xint    loop;
  1197. X
  1198. X   for (loop = 0; loop < MAXCLASSXMITTERS; loop++)
  1199. X      if (classptr->slots[loop] != 'X') {
  1200. X         classptr->slots[loop] = 'X';
  1201. X         return loop;
  1202. X      }
  1203. X
  1204. X   logerr("(getclassslot) Too many xmitters for class %s", classptr->classname);
  1205. X   return -1;
  1206. X
  1207. X}
  1208. X
  1209. X/*************************************************************************/
  1210. X/* FUNCTION  : freeclassslot                                             */
  1211. X/* PURPOSE   :                                                           */
  1212. X/* ARGUMENTS : slot number to free and a pointer to the class structure  */
  1213. X/*************************************************************************/
  1214. X
  1215. Xvoid    freeclassslot(classptr, slot)
  1216. Xstruct    class    *classptr;
  1217. Xint        slot;
  1218. X
  1219. X{
  1220. X
  1221. X   classptr->slots[slot] = '.';
  1222. X
  1223. X}
  1224. X
  1225. X/*************************************************************************/
  1226. X/* FUNCTION  : idle                                                      */
  1227. X/* PURPOSE   : Set newsxd to idle mode.  Don't process xmitter queue...  */
  1228. X/* ARGUMENTS : none                                                      */
  1229. X/*************************************************************************/
  1230. X
  1231. Xvoid
  1232. Xidle()
  1233. X
  1234. X{
  1235. X
  1236. X   daemon_idle = 1;
  1237. X
  1238. X}
  1239. X
  1240. X/*************************************************************************/
  1241. X/* FUNCTION  : reset                                                     */
  1242. X/* PURPOSE   : Kill all outstanding transmitters and idle newsxd.        */
  1243. X/* ARGUMENTS : none                                                      */
  1244. X/*************************************************************************/
  1245. X
  1246. Xvoid
  1247. Xreset()
  1248. X
  1249. X{
  1250. X
  1251. X   kill_children(0);
  1252. X   daemon_idle = 1;
  1253. X
  1254. X}
  1255. X
  1256. X#ifdef CNEWSLOCKING
  1257. X
  1258. X/*************************************************************************/
  1259. X/* FUNCTION  : unprivileged                                              */
  1260. X/* PURPOSE   : keep the cnews libraries happy.                           */
  1261. X/* ARGUMENTS : none used.                                                */
  1262. X/*************************************************************************/
  1263. X
  1264. Xint
  1265. Xunprivileged(reason)
  1266. Xchar    *reason;
  1267. X{
  1268. X
  1269. X}
  1270. X
  1271. X#endif CNEWSLOCKING
  1272. END_OF_FILE
  1273.   if test 10869 -ne `wc -c <'util.c'`; then
  1274.     echo shar: \"'util.c'\" unpacked with wrong size!
  1275.   fi
  1276.   # end of 'util.c'
  1277. fi
  1278. if test -f 'version.c' -a "${1}" != "-c" ; then 
  1279.   echo shar: Will not clobber existing file \"'version.c'\"
  1280. else
  1281.   echo shar: Extracting \"'version.c'\" \(10181 characters\)
  1282.   sed "s/^X//" >'version.c' <<'END_OF_FILE'
  1283. X/*
  1284. X * #include <legal/bs.h>
  1285. X >
  1286. X > Copyright (c) 1989 Washington University in Saint Louis, Missouri and
  1287. X > Chris Myers. All rights reserved.
  1288. X >
  1289. X > Permission is hereby granted to copy, reproduce, redistribute or
  1290. X > otherwise use this software as long as: (1) there is no monetary
  1291. X > profit gained specifically from the use or reproduction of this
  1292. X > software, (2) it is not sold, rented, traded, or otherwise marketed,
  1293. X > (3) the above copyright notice and this paragraph is included
  1294. X > prominently in any copy made, and (4) that the name of the University
  1295. X > is not used to endorse or promote products derived from this software
  1296. X > without the specific prior written permission of the University.
  1297. X > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1298. X > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1299. X > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1300. X >
  1301. X * newsxd: a daemon for controlling the transmission of news
  1302. X *
  1303. X * Written by
  1304. X * Chris Myers                              Internet: chris@wugate.wustl.edu
  1305. X * Software Engineer                            UUCP: ...!uunet!wugate!chris
  1306. X * Office of the Network Coordinator              BITNET: chris@wunet.bitnet
  1307. X * Washington University in Saint Louis
  1308. X *
  1309. X * HISTORY:
  1310. X * Version 0.1:   first written in perl.  A grand experiment that just didn't
  1311. X *                work very reliably (no reflection on the quality of perl, it
  1312. X *                just wasn't meant to do this kind of thing).
  1313. X *
  1314. X * Version 1.0:   first C version
  1315. X *
  1316. X *         1.1:   added per-host locking
  1317. X *         1.2:   added maxload qualifier
  1318. X *         1.2.1: added time to live qualifier
  1319. X *
  1320. X *                SOURCE CODE INADVERTANTLY DESTROYED (SIGH)
  1321. X *                Oh well, it needed rewriting anyway. :-)
  1322. X *
  1323. X * Version 2.0:   here we go again. No per-host locking right now :-(
  1324. X *                Removed all static limits on the number of transmission
  1325. X *                classes and hosts.  Everything is now malloc'ed.
  1326. X *         2.0.1: added penalty time to time-to-live qualifier to allow other
  1327. X *                hosts to get news transmitters started.
  1328. X *         2.1:   Added the capability to specify a different transmission
  1329. X *                program (and parameters) for each transmission class.  This
  1330. X *                was the motive for the name change from nntpxd to newsxd.
  1331. X *         2.1.1: fixed bug caused by defunct transmitters which finally
  1332. X *                overran the ttl (did not do proper cleanup).
  1333. X *         2.1.2: added patches for Pyramid and BSD 4.3 support from Warren
  1334. X *                Lavallee and Jim Lowe.
  1335. X *         2.1.3: fixed bugs in calculating the ttl penalty and start/stop
  1336. X *                time ranges
  1337. X *         2.1.4: fixed bug in read_config where the loop went 1 past the end
  1338. X *                of the options for a transmission class.  This could cause
  1339. X *                the last parameter on a longer preceeding class line to be
  1340. X *                carried over to the subsequent classes.
  1341. X *         2.1.5: somehow the default value for nntplogs slipped away from the
  1342. X *                code.  Put it back in where it belongs.
  1343. X *         2.1.6: added inter-host startup interval for classes so that newsxd
  1344. X *                doesn't start up too many daemons at once
  1345. X *         2.1.7: fix stupid bug created in earlier patch where I set argptr[x]
  1346. X *                to NULL (what it was supposed to be) and then blithly reset it
  1347. X *                to something else -- preventing EXECing the program specified
  1348. X *                in an XMIT option.  ARGH.
  1349. X *         2.1.8: ARGH! Left out the code to make sure a transmitter for each
  1350. X *                host wasn't started up more often than <interval> seconds.
  1351. X *         2.2:   Cut down on the size of the wishlist by adding a bunch of
  1352. X *                features (and hopefully no more bugs):
  1353. X *                - syslog logging
  1354. X *                - lots of range/value checking on inputs
  1355. X *                - sort host/class names when inserting into list
  1356. X *                - move all configuration parameters into newsxd.h
  1357. X *                - add more error messages
  1358. X *                - document code even more
  1359. X *                - allow reconfiguration without killing outstanding xmitters
  1360. X *                - add a 'nobatchfile' switch
  1361. X *                - allocation of alternate xmitter parameters is now dynamic
  1362. X *                - Per-host delta-nice values for transmitters
  1363. X *                - make code more readable
  1364. X *                - write a manpage
  1365. X *         2.3:   Add SIGUSR1, SIGUSR2 to {en,dis}able debugging while running
  1366. X *                Shift the order of syslog initialization and switch to daemon
  1367. X *                Fix a "go past end of the array sometimes" bug in getclass().
  1368. X *                add "reason" to status display to show why xmitter not running
  1369. X *                in xmit options, %f=flags,%w=workfile,%b=batchfile,%h=hostname
  1370. X *                make transmission of news to hosts 'fair'
  1371. X *                minimize a race in run_queue if SIGQUIT causes reconfiguration
  1372. X *                change start/stop times to use UUCP-style permissible times
  1373. X *         2.3.1: fix bug in incr xmitsernum when only one service class in use
  1374. X *                enable fair transmission code even if maxxmits > class members
  1375. X *                change use of strpbrk to strchr and make strchr #define'd
  1376. X *         2.4:   add per-host flags
  1377. X *                added check for multiply-defined host/class in add{host,class}
  1378. X *                zero classptr->members in addclass to allow reconfiguration
  1379. X *         2.4.1: classptr->members++ in addhost was in the wrong spot
  1380. X *                buffer declaration for FAKESYSLOG had trailing ; should be ,
  1381. X *                log a reinitialization message after getting SIGHUP
  1382. X *                add -v switch to show version and logging
  1383. X *                if debugging == ON in daemon mode, don't dump status to stderr
  1384. X *                was closing pidfile with close() rather than fclose()
  1385. X *                change comments in xmit_done() to show sig==0 is NOHANG
  1386. X *                validtime() was mangling the valid times string
  1387. X *                parsetime() sometimes said a good time was not valid
  1388. X *                addhost() now resorts host list on reconfiguration
  1389. X *         2.4.2: modify xmit_done() to almost always use WNOHANG on wait calls
  1390. X *                add_host() was improperly decrementing classptr->members
  1391. X *                When debugging changes, log "On"/"Off" not the value (0/-1)
  1392. X *                get rid of remaining code for obsolete "nntpxmit" keyword
  1393. X *                finish updating comments, changing "nntpxmit" to "transmitter"
  1394. X *         2.5:   sigsetmask(0) to allow SIGCHLD in xmit_done(); don't lose kids
  1395. X *                modify "Why Not Running" messages slightly for readability
  1396. X *                xmit_done() now loops to catch all completed transmitters
  1397. X *                run_queue() now checks for MIA transmitters and cleans 'em up
  1398. X *                if no classes defined, dump_config() now returns immediately
  1399. X *                break the source apart into several files from one big'un
  1400. X *                class options are default, w/host options overriding
  1401. X *                   [ttl, interval, nice, maxload]
  1402. X *                run_queue() was setting whynotrunning wrong for active xmits
  1403. X *                moved ttl penalty check into "host gave up chance" code to
  1404. X *                   prevent a penalized host from blocking others
  1405. X *                added SIGIO to idle newsxd until SIGHUP is received
  1406. X *                added class slots
  1407. X *                added faster pid->host mapping data structure
  1408. X *                added SIGTRAP to dump internal data structures for debugging
  1409. X *         2.5.1: apply "lint" fixes from Andrew Partan <asp@uunet.uu.net>
  1410. X *                close and reopen logfiles on SIGHUP <asp@uunet.uu.net>
  1411. X *                put Why Not reasons in static array, use everywhere
  1412. X *                process.c: in fork()ed child, call _exit() not exit()
  1413. X *                check for duplicate newsxd running
  1414. X *                add support for per-class transmitter debugging flags
  1415. X *                fix an open file leak in config.c:read_config()
  1416. X *                add SIGIOT to kill all transmitters and idle newsxd
  1417. X *                add setuid(geteuid()), setgid(getegid()) in main()
  1418. X *                fix some potential null-ptr dereferencing problems in config.c
  1419. X *                fix array-index overrun problem in config.c <asp@uunet.uu.net>
  1420. X *                remove pidfile and statusfile on shutdown unless debug|DEBUG
  1421. X *                flock() the work file before EXECing the transmitter
  1422. X *                support CNEWS-style locking to prevent races on the work file
  1423. X *                restore default signal action after fork() for transmitter
  1424. X *
  1425. X * SPECIAL THANKS TO:
  1426. X *
  1427. X * Alpha tester:  John Coolidge <coolidge@brutus.cs.uiuc.edu>
  1428. X *
  1429. X * Beta testers:  Warren Lavallee <warren@schizo.samsung.com>
  1430. X *                Don Thomson <thomson@macc.wisc.edu>
  1431. X *                Michael A. Cooper <mcooper@usc.edu>
  1432. X *                Jim Lowe <james@csd4.csd.uwm.edu>
  1433. X *                David C. Lawrence <tale@pawl.rpi.edu>
  1434. X *                John Coolidge <coolidge@brutus.cs.uiuc.edu>
  1435. X *                Lloyd W. Taylor <lloyd@aplcen.apl.jhu.edu>
  1436. X *                Dave Alden <alden@shape.mps.ohio-state.edu>
  1437. X *                Greg Hackney <root@texbell.sbc.com>
  1438. X *                Rick Adams <rick@uunet.uu.net>
  1439. X *                Andrew Partan <asp@uunet.uu.net>
  1440. X *
  1441. X * This software has been tested on the following systems:
  1442. X *
  1443. X * DECstation 3100, Ultrix 3.1
  1444. X * DEC VAX 8810, Ultrix 3.1
  1445. X * Sun 3/60, SunOS 4.0.1
  1446. X * Sun 3/180, SunOS 4.0.3
  1447. X * Pyramid DualPort OSx
  1448. X * DEC MicroVAX-II, BSD 4.3 UNIX
  1449. X * DEC MicroVAX-II, Mt Xinu MORE/BSD 4.3
  1450. X *
  1451. X * Wishlist:
  1452. X *
  1453. X * - add logging of transmitter resource usage
  1454. X * - Exponential backoff for failed transmission attempts
  1455. X * - Per-host locking, using shlock-style locks
  1456. X * - ability to specify min. # of articles queued before xmission starts
  1457. X * - add per-class workfile and batchfile definitions
  1458. X * - add per-host maximum delay between transmitter startups
  1459. X *
  1460. X */
  1461. END_OF_FILE
  1462.   if test 10181 -ne `wc -c <'version.c'`; then
  1463.     echo shar: \"'version.c'\" unpacked with wrong size!
  1464.   fi
  1465.   # end of 'version.c'
  1466. fi
  1467. echo shar: End of archive 2 \(of 3\).
  1468. cp /dev/null ark2isdone
  1469. MISSING=""
  1470. for I in 1 2 3 ; do
  1471.     if test ! -f ark${I}isdone ; then
  1472.     MISSING="${MISSING} ${I}"
  1473.     fi
  1474. done
  1475. if test "${MISSING}" = "" ; then
  1476.     echo You have unpacked all 3 archives.
  1477.     rm -f ark[1-9]isdone
  1478. else
  1479.     echo You still must unpack the following archives:
  1480.     echo "        " ${MISSING}
  1481. fi
  1482. exit 0
  1483. exit 0 # Just in case...
  1484.